package com.example.serverdemo.netty.device_tcp_server.function_module;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ArrayUtil;
import com.example.serverdemo.dto.CentralControllerProtocolDto;
import com.example.serverdemo.netty.device_tcp_server.handler.DeviceHandler;
import com.example.serverdemo.netty.device_tcp_server.type.FunctionType;
import com.example.serverdemo.utils.crcutls.LightControllerCRCUtil;
import com.example.serverdemo.utils.log.PrintLogUtil;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Queue;

public class CentralControllerFunctionModule extends BaseFunctionModule{
    private static final int  PACKET_SIZE=512;
    private FunctionType functionType;
    private int processControlIdentification;
    private Queue<Byte[]> protocolDataPackets;
    public CentralControllerFunctionModule(DeviceHandler handler) {
        this.init();
        this.bindDeviceHandler(handler);
    }

    @Override
    protected void init() {
        super.init();
        this.protocolDataPackets = new ArrayDeque<>();
        this.processControlIdentification = 0;
    }
    @Override
    protected boolean success(Object obj) {
        try {
            switch (this.functionType){
                case CentralControllerProtocolConfiguration:
                    this.configurationProtocolSuccess(obj);
                    break;
            }
            return true;
        }catch (Exception e){
            PrintLogUtil.printError(this,e);
        }
        return false;
    }
    @Override
    protected boolean failed(String msg) {
        try {
            switch (this.functionType){
                case CentralControllerProtocolConfiguration:
                    this.configurationProtocolFailed("Central Controller Protocol Configuration Failed :" + msg);
                    break;
            }
            return true;
        }catch (Exception e){
            PrintLogUtil.printError(this,e);
        }
        return false;
    }
    private void initParams(){
        this.handler.currentFunctionType = FunctionType.Null;
        this.functionType = FunctionType.Null;
        this.initConfigurationParameter();
        this.handler.setFunctionKey(true);

    }
    @Override
    public boolean msgDistributionTransactionManagement(byte[] msg) {
        switch (this.functionType) {
            case CentralControllerProtocolConfiguration:
                return this.configurationProtocolMsgManagement(msg);
        }
        return false;
    }
    private void initConfigurationParameter(){
        if (this.protocolDataPackets != null)this.protocolDataPackets.clear();
        this.processControlIdentification = 0;
    }
    public boolean configurationProtocol(int protocolId){
        try {
            if (!this.handler.isFunctionKey()) return false;
            if (this.handler.deviceId == null) return false;
            this.handler.setFunctionKey(false);
            this.functionType = FunctionType.CentralControllerProtocolConfiguration;
            this.initConfigurationParameter();
            this.processControlIdentification = 0;
            CentralControllerProtocolDto protocol = this.handler.protocolInfoService.queryProtocolInfo(protocolId);
            byte[] protocolData = protocol.toHexData();
            for (int index = 0;index < protocolData.length;index += 512){
                this.protocolDataPackets.add(Convert.toByteArray(ArrayUtil.sub(protocolData, index, index + 512)));
            }
            this.configurationProtocolTask();
            System.out.println("configurationProtocol");
            return true;
        }catch (Exception e){
            PrintLogUtil.printError(this,e);
        }
        return false;
    }
    private boolean configurationProtocolTask(){
        try {
            ArrayList<String> params = new ArrayList<>();
            byte[] data;
            switch (this.processControlIdentification){
                case 0:
                    data = "lk".getBytes();
                    params.add("lk");
                    params.add("" + data.length);
                    this.sendOrder("CenterControl",params, Convert.intToByte(0x05),Convert.intToByte(this.handler.currentDeviceInfo.getDeviceAddress()),true);
                    break;
                case 1:
                    data = "lk".getBytes();
                    this.sendData(data, Convert.intToByte(0x02),Convert.intToByte(this.handler.currentDeviceInfo.getDeviceAddress()),true);
                    break;
                case 3:
                    data = "dk".getBytes();
                    params.add("dk");
                    params.add("" + data.length);
                    this.sendOrder("CenterControl",params, Convert.intToByte(0x05),Convert.intToByte(this.handler.currentDeviceInfo.getDeviceAddress()),true);
                    break;
                case 4:
                    data = "dk".getBytes();
                    this.sendData(data, Convert.intToByte(0x02),Convert.intToByte(this.handler.currentDeviceInfo.getDeviceAddress()),true);
                    break;
                case 6:
                    params.add("dk");
                    params.add(String.valueOf(256 * 8 * 8 + 2 * 32));
                    this.sendOrder("CenterControl",params, Convert.intToByte(0x05),Convert.intToByte(this.handler.currentDeviceInfo.getDeviceAddress()),true);
                    break;
                default:
                    if (this.processControlIdentification > 6 && this.processControlIdentification % 2 != 0 && this.protocolDataPackets.size() > 0){
                        Byte[] bytes = this.protocolDataPackets.remove();
                        byte[] crcBuff = LightControllerCRCUtil.getCrc(Convert.toPrimitiveByteArray(bytes));
                        byte[] crc = new byte[]{crcBuff[3],crcBuff[2]};
                        data = ArrayUtil.addAll(Convert.toPrimitiveByteArray(bytes), crc);
                        byte mark = this.protocolDataPackets.size() > 0 ? Convert.intToByte(0x06):Convert.intToByte(0x02);
                        this.sendData(data,mark,Convert.intToByte(this.handler.currentDeviceInfo.getDeviceAddress()),true);
                    }else if (this.processControlIdentification > 6 && this.processControlIdentification % 2 != 0 && this.protocolDataPackets.size() == 0){
                        this.success(null);
                    }
                    break;
            }
            return true;
        }catch (Exception e){
            PrintLogUtil.printError(this,e);
        }
        return false;
    }
    private boolean configurationProtocolMsgManagement(byte[] msg){
        try {
            byte[] data = ArrayUtil.sub(msg,8,msg.length);
            String msgStr = new String(data);
            System.out.println("msg : " + msgStr);
            this.stopOverTimeDetectionTask();
            switch (msgStr){
                case "Ok:Decode":
                case "Done":
                case "SendNext":
                case "ack\r\n":
                    this.processControlIdentification++;
                    this.configurationProtocolTask();
                    break;
                default:
                    this.failed("Receive Error Message :" + msgStr);
            }
            return true;
        }catch (Exception e){
            PrintLogUtil.printError(this,e);
        }
        return false;
    }
    private void configurationProtocolSuccess(Object obj){
        PrintLogUtil.printInfo(this,"Configuration Protocol Success");
        this.initParams();
        this.handler.closeHandler();
    }
    private void configurationProtocolFailed(String msg){
        PrintLogUtil.printInfo(this,"Configuration Protocol Failed :" + msg);
        this.initParams();
    }
}
